package org.slusk.thynwor.test;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import org.slusk.thynwor.corestructures.Environment;
import org.slusk.thynwor.neat.ActivatableNetFactory;
import org.slusk.thynwor.util.Util;

import com.anji.hyperneat.nd.NDActivatorArray;
import com.anji.util.Properties;

public class ChampionTester {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
    	Properties props = new Properties();
        props.loadFromResources(args);
		int simulationsToRun = props.getIntProperty("Evaluation.simulationsToRun");
		int maxNumTrainingEpochs = props.getIntProperty("TrainingBank.maxNumTrainingEpochs", 4);
		float mseThreshold = props.getFloatProperty("TrainingBank.mseThreshold", 0.2F);
		int timeSteps = props.getIntProperty("Evaluation.timeSteps");
		int timeStepsToTrain = props.getIntProperty("Evaluation.timeStepsToTrain", 0);
		int trainingBankIterationsToPerform = props.getIntProperty("Evaluation.trainingBankIterationsToPerform",2);
		boolean usePreTraining = props.getBooleanProperty("Evaluation.usePreTraining",true);
		int sparseTimeStepCount = 0;
		ArrayList<Float> rndFoodCollectedArray = new ArrayList<Float>(simulationsToRun);
		ArrayList<Float> rndHitObstacleArray = new ArrayList<Float>(simulationsToRun);
		ArrayList<Float> rndDroppedFoodArray = new ArrayList<Float>(simulationsToRun);

		Environment rndEnv = new Environment(props);
		Environment sparse = new Environment(props);
		sparse.setLayoutName("configs/sparseLayout.xml");
		sparse.setMaintainFood(0);
		NDActivatorArray sasasNetArray = ActivatableNetFactory.createGridNets(props);
		
		rndEnv.setSasasNetArray(sasasNetArray);
		sparse.setSasasNetArray(sasasNetArray);
		
		if (usePreTraining) {
			// Pre-Training phase
			rndEnv.performTraining("configs/layout.xml", timeStepsToTrain, trainingBankIterationsToPerform, maxNumTrainingEpochs, mseThreshold);
		}
		
		rndEnv.setUseOnlineReinforcement(false);
		sparse.setUseOnlineReinforcement(false);
		
		for (int i = 0; i < simulationsToRun; i++) {
			rndEnv.resetLayout();
			rndEnv.runSim(timeSteps);
			rndFoodCollectedArray.add((float)rndEnv.getFoodCollected());
			rndHitObstacleArray.add((float)rndEnv.getHitObstacle() + (float)rndEnv.getHandsFull());
			rndDroppedFoodArray.add((float)rndEnv.getDroppedFood());
		}
		
		sparse.resetLayout();
		while(sparse.getFoodCollected() < 8 && sparseTimeStepCount < 200) {
			sparseTimeStepCount++;
			sparse.runSim(1);
		}
		int sparseFoodCollected = sparse.getFoodCollected();
		int sparseHitObstacle = sparse.getHitObstacle() + sparse.getHandsFull();
		int sparseDroppedFood = sparse.getDroppedFood();
		
		dumpResultsToFile(props, rndFoodCollectedArray, rndHitObstacleArray, rndDroppedFoodArray, sparseFoodCollected, sparseHitObstacle, sparseDroppedFood, sparseTimeStepCount);
	}

	
	private static void dumpResultsToFile(Properties props
			, ArrayList<Float> rndFoodCollectedArray
			, ArrayList<Float> rndHitObstacleArray
			, ArrayList<Float> rndDroppedFoodArray
			, int sparseFoodCollected
			, int sparseHitObstacle
			, int sparseDroppedFood
			, int sparseTimeElapsed) throws IOException {
		
		BufferedWriter out = new BufferedWriter(new FileWriter(props.getProperty("Evaluation.outputFile")));

		out.write("Chromosome," + props.getProperty("LoadChromosomePath"));
		out.write("\n");
		
		out.write("Run#,RandomFoodCollected,RandomHitObstacle,RandomDroppedFood");
		out.write("\n");
		
		// write data
		for (int run = 0; run < props.getIntProperty("Evaluation.simulationsToRun"); run++) {
			out.write(run + ",");
			out.write(rndFoodCollectedArray.get(run)+ ",");
			out.write(rndHitObstacleArray.get(run) + ",");
			out.write(rndDroppedFoodArray.get(run) + ",");
			out.write("\n");
		}
		
		double avgFoodCollected = Util.averageResults(rndFoodCollectedArray);
		double avgHitObstacle = Util.averageResults(rndHitObstacleArray);
		double avgDroppedFood = Util.averageResults(rndDroppedFoodArray);
		
		out.write("\n");
		out.write("RandomFoodAverage," + avgFoodCollected + ",(" + Util.calculateStdDev(rndFoodCollectedArray, avgFoodCollected)+ ")");
		out.write("\n");
		out.write("RandomHitObstacle," + avgHitObstacle + ",(" + Util.calculateStdDev(rndHitObstacleArray, avgHitObstacle)+ ")");
		out.write("\n");
		out.write("RandomDroppedFood," + avgDroppedFood + ",(" + Util.calculateStdDev(rndDroppedFoodArray, avgDroppedFood)+ ")");
		out.write("\n");
		out.write("\n");
		out.write("Sparse Food Collected," + sparseFoodCollected);
		out.write("\n");
		out.write("Sparse Hit Obstacles," + sparseHitObstacle);
		out.write("\n");
		out.write("Sparse Dropped Food," + sparseDroppedFood);
		out.write("\n");
		out.write("Sparse Time Elapsed," + sparseTimeElapsed);
		out.write("\n");
		out.close();
		
	}

}
